Hystrix 简单请求合并

作者: 李多多 日期: 2020-08-07
Spring Cloud
Hystrix 简单请求合并

频繁的调用provider接太浪费了, 就有了将多个请求合并为一个请求的方式。
首先在provider中提供一个请求合并的接口:

@RestController
public class UserController {
/**【既可以处理多个,也可以处理单个请求】
*单个请求的话,List中只有一项数据
*假设 consumer 传过来的多个id格式是 1,2,3,4....*/
@GetMapping("/user/{ids}")
public List<User> getUserByIds(@PathVariable String ids){
System.out.println(ids);
String[] split = ids.split(",");
List<User> user = new ArrayList<>();
for(String s : split){
User user1 = new User();
user1.setId(Integer.parseInt(s));
user.add(user1);
}
return user;
}
}

然后在Hystrix中定义UserService:

@Service
public class UserService {

@Autowired
RestTemplate restTemplate;


public List<User> getUsersByIds(List<Integer> ids){
User[] users = restTemplate.getForObject("http://provider/user/{1}", User[].class, StringUtils.join(ids, ","));
return Arrays.asList(users);
}
}

接下来定义 UserBatchCommand ,相当于我们之前的 HelloCommand:

public class UserBatchCommand extends HystrixCommand<List<User>> {
private List<Integer> ids;
private UserService userService;

public UserBatchCommand(List<Integer> ids, UserService userService) {
super(HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("batchCmd")).andCommandKey(HystrixCommandKey.Factory.asKey("batchKey")));
this.ids = ids;
this.userService = userService;
}

@Override
protected List<User> run() throws Exception {
return userService.getUsersByIds(ids);
}
}

一、最后定请求合并方法,【继承方式,做为了解】:

public class UserCollapseCommand extends HystrixCollapser<List<User>, User, Integer> {
private UserService userService;
private Integer id;

public UserCollapseCommand(UserService userService, Integer id) {
super(HystrixCollapser.Setter.withCollapserKey(HystrixCollapserKey.Factory.asKey("UserCollapseCommand")).andCollapserPropertiesDefaults(HystrixCollapserProperties.Setter().withTimerDelayInMilliseconds(200)));
this.userService = userService;
this.id = id;
}

/**
* 请求参数
*
* @return
*/
@Override
public Integer getRequestArgument() {
return id;
}

/**
* 请求合并的方法
*
* @param collection
* @return
*/
@Override
protected HystrixCommand<List<User>> createCommand(Collection<CollapsedRequest<User, Integer>> collection) {
List<Integer> ids = new ArrayList<>(collection.size());
for (CollapsedRequest<User, Integer> userIntegerCollapsedRequest : collection) {
ids.add(userIntegerCollapsedRequest.getArgument());
}
return new UserBatchCommand(ids, userService);
}

/**
* 请求结果分发
*
* @param users
* @param collection
*/
@Override
protected void mapResponseToRequests(List<User> users, Collection<CollapsedRequest<User, Integer>> collection) {
int count = 0;
for (CollapsedRequest<User, Integer> request : collection) {
request.setResponse(users.get(count++));
}
}
}

然后测试调用:

@GetMapping("/hello5")
public void hello5() throws ExecutionException,InterruptedException{
HystrixRequestContext ctx = HystrixRequestContext.initializeContext();
UserCollapseCommand cmd1 = new UserCollapseCommand(userService, 99);
UserCollapseCommand cmd2 = new UserCollapseCommand(userService, 98);
UserCollapseCommand cmd3 = new UserCollapseCommand(userService, 97);

Future<User> q1 = cmd1.queue();
Future<User> q2 = cmd2.queue();
Future<User> q3 = cmd3.queue();

User u1 = q1.get();
User u2 = q2.get();
User u3 = q3.get();

System.out.println(u1);
System.out.println(u2);
System.out.println(u3);
Thread.sleep(2000);//睡2秒就变成两次请求,
UserCollapseCommand cmd4 = new UserCollapseCommand(userService, 96);
Future<User> q4 = cmd4.queue();
User u4 = q4.get();
System.out.println(u4);
ctx.close();

}

二、通过注解实现请求合并【掌握】:

@Service
public class UserService {

@Autowired
RestTemplate restTemplate;

/**
* 注解方式实现请求合并
* @param id
* @return HystrixCollapse
*【重要:@HystrixCollapser 注解指定批处理方法】
*/
@HystrixCollapser(batchMethod = "getUsersByIds",collapserProperties = {@HystrixProperty(name = "timerDelayInMilliseconds",value = "200")})
public Future<User> getUserById(Integer id) {
return null;
}

@HystrixCommand
public List<User> getUsersByIds(List<Integer> ids){
User[] users = restTemplate.getForObject("http://provider/user/{1}", User[].class, StringUtils.join(ids, ","));
return Arrays.asList(users);
}
}

测试方法:

/**
* 注解方式实现请求合并 测试方法
* @throws ExecutionException
* @throws InterruptedException
*/
@GetMapping("/hello6")
public void hello6() throws ExecutionException, InterruptedException {
HystrixRequestContext ctx = HystrixRequestContext.initializeContext();
Future<User> q1 = userService.getUserById(99);
Future<User> q2 = userService.getUserById(98);
Future<User> q3 = userService.getUserById(97);
User u1 = q1.get();
User u2 = q2.get();
User u3 = q3.get();
System.out.println(u1);
System.out.println(u2);
System.out.println(u3);
Thread.sleep(2000);
Future<User> q4 = userService.getUserById(96);
User u4 = q4.get();
System.out.println(u4);
ctx.close();
}

小结 :@HystrixCollapser(batchMethod = “getUserByIds”,collapserProperties = {@HystrixProperty(name = “timerDelayInMilliseconds”,value = “200”)})

@HystrixCommand

代码地址:https://github.com/astronger/springcloud-simple-samples